<template>
  <div ref="tableRef">
    <NDataTable
      :columns="columnList"
      :data="issueList"
      :striped="true"
      :bordered="true"
      :loading="loading"
      :row-key="(issue: ComposedIssue) => issue.name"
      :row-props="rowProps"
      class="review-issue-table"
    />
  </div>
</template>

<script lang="tsx" setup>
import { useElementSize } from "@vueuse/core";
import { head } from "lodash-es";
import type { DataTableColumn } from "naive-ui";
import { NPerformantEllipsis, NDataTable } from "naive-ui";
import { computed, watch, ref } from "vue";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
import DatabaseInfo from "@/components/DatabaseInfo.vue";
import { databaseForSpec } from "@/components/IssueV1";
import IssueLabelSelector, {
  getValidIssueLabels,
} from "@/components/IssueV1/components/IssueLabelSelector.vue";
import IssueStatusIconWithTaskSummary from "@/components/IssueV1/components/IssueStatusIconWithTaskSummary.vue";
import { ProjectNameCell } from "@/components/v2/Model/DatabaseV1Table/cells";
import { emitWindowEvent } from "@/plugins";
import { useSheetV1Store } from "@/store";
import { type ComposedIssue } from "@/types";
import { humanizeTs, flattenSpecList, extractIssueUID } from "@/utils";

const { t } = useI18n();

const columnList = computed((): DataTableColumn<ComposedIssue>[] => {
  const columns: (DataTableColumn<ComposedIssue> & { hide?: boolean })[] = [
    {
      key: "title",
      title: t("issue.table.name"),
      resizable: true,
      render: (issue) => {
        return (
          <div class="flex items-center overflow-hidden space-x-2">
            <IssueStatusIconWithTaskSummary issue={issue} />
            <div class="whitespace-nowrap text-control">
              {issue.projectEntity.key}-{extractIssueUID(issue.name)}
            </div>
            <NPerformantEllipsis class="flex-1 truncate">
              {{
                default: () => <span>{issue.title}</span>,
                tooltip: () => (
                  <div class="whitespace-pre-wrap break-words break-all">
                    {issue.title}
                  </div>
                ),
              }}
            </NPerformantEllipsis>
          </div>
        );
      },
    },
    {
      key: "project",
      title: t("common.project"),
      width: 144,
      resizable: true,
      hide: !props.showProject,
      render: (issue) => (
        <ProjectNameCell project={issue.projectEntity} mode={"ALL_SHORT"} />
      ),
    },
    {
      key: "labels",
      title: t("common.labels"),
      width: 144,
      resizable: true,
      render: (issue) => {
        const labels = getValidIssueLabels(
          issue.labels,
          issue.projectEntity.issueLabels
        );
        if (labels.length === 0) {
          return "-";
        }
        return (
          <IssueLabelSelector
            disabled={true}
            selected={labels}
            size="small"
            maxTagCount="responsive"
            project={issue.projectEntity}
          />
        );
      },
    },
    {
      key: "database",
      title: t("common.database"),
      width: 300,
      resizable: true,
      hide: !showExtendedColumns.value,
      render: (issue) => {
        const database = issueRelatedDatabase(issue);
        if (!database) {
          return "-";
        }
        return <DatabaseInfo database={database} />;
      },
    },
    {
      key: "statement",
      title: t("common.statement"),
      resizable: true,
      ellipsis: true,
      hide: !showExtendedColumns.value,
      render: (issue) => {
        const statement = issueRelatedStatement(issue);
        return statement || "-";
      },
    },
    {
      key: "updateTime",
      title: t("issue.table.updated"),
      width: 150,
      resizable: true,
      hide: !showExtendedColumns.value,
      render: (issue) => humanizeTs((issue.updateTime?.getTime() ?? 0) / 1000),
    },
  ];
  return columns.filter((column) => !column.hide);
});

const props = withDefaults(
  defineProps<{
    issueList: ComposedIssue[];
    loading?: boolean;
    showProject: boolean;
  }>(),
  {
    loading: true,
    showProject: true,
  }
);

const router = useRouter();
const sheetStore = useSheetV1Store();

const tableRef = ref<HTMLDivElement>();
const { width: tableWidth } = useElementSize(tableRef);
const showExtendedColumns = computed(() => {
  return tableWidth.value > 800;
});

const rowProps = (issue: ComposedIssue) => {
  return {
    style: "cursor: pointer;",
    onClick: (e: MouseEvent) => {
      emitWindowEvent("bb.issue-detail", {
        uid: extractIssueUID(issue.name),
      });
      const route = router.resolve({
        path: `/${issue.name}`,
      });
      const url = route.fullPath;
      if (e.ctrlKey || e.metaKey) {
        window.open(url, "_blank");
      } else {
        router.push(url);
      }
    },
  };
};

const issueRelatedDatabase = (issue: ComposedIssue) => {
  const spec = head(flattenSpecList(issue.planEntity));
  if (!spec) {
    return;
  }
  return databaseForSpec(issue, spec);
};

const issueRelatedStatement = (issue: ComposedIssue) => {
  const spec = head(flattenSpecList(issue.planEntity));
  const sheetName = spec?.changeDatabaseConfig?.sheet;
  if (!spec || !sheetName) {
    return;
  }
  const sheet = sheetStore.getSheetByName(sheetName);
  if (!sheet) {
    return;
  }
  const statement = new TextDecoder().decode(sheet.content);
  return statement;
};

watch(
  () => props.issueList,
  (list) => {
    // Prepare the sheet for each issue.
    for (const issue of list) {
      const spec = head(flattenSpecList(issue.planEntity));
      const sheetName = spec?.changeDatabaseConfig?.sheet;
      if (!spec || !sheetName) {
        continue;
      }
      sheetStore.getOrFetchSheetByName(sheetName);
    }
  }
);
</script>

<style scoped lang="postcss">
:deep(.n-base-selection-tags) {
  @apply !bg-transparent !p-0;
}
:deep(.n-base-suffix),
:deep(.n-base-selection__border),
:deep(.n-base-selection__state-border) {
  @apply !hidden;
}
</style>
